package cn.shengchao.controler.question;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.shengchao.examstar.ai.application.service.AIWorkflowApplicationService;
import cn.shengchao.examstar.ai.domain.repository.IAiChatFreeSunRepository;
import cn.shengchao.examstar.ai.domain.valueobject.SpecificationType;
import cn.shengchao.examstar.ai.domain.valueobject.UserId;
import cn.shengchao.examstar.ai.infrastructure.external.ai.agent.QuestionCorrectAgent;
import cn.shengchao.examstar.ai.shared.enums.AiChatFreeType;
import cn.shengchao.examstar.distribute.infrastrure.po.DistributeNodeInfo;
import cn.shengchao.examstar.distribute.infrastrure.service.DistributeNodeInfoService;
import cn.shengchao.examstar.knowledge.acl.ports.repositories.IKnowledgePointRepository;
import cn.shengchao.examstar.knowledge.domain.entity.KnowledgePoint;
import cn.shengchao.examstar.knowledge.domain.entity.KnowledgeTag;
import cn.shengchao.examstar.product.acl.ports.repositories.INodeKnowledgePointRepository;
import cn.shengchao.examstar.product.infrastructure.dao.po.NodeKnowledgePoint;
import cn.shengchao.examstar.rpc.base.PageResult;
import cn.shengchao.examstar.rpc.distribute.enums.DistributeSaleRoleEnum;
import cn.shengchao.examstar.rpc.knowledge.req.KnowledgeReq;
import cn.shengchao.examstar.rpc.knowledge.resp.KnowledgePointDto;
import cn.shengchao.util.helper.LoginHelper;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.shengchao.examstar.rpc.question.api.IErrorQuestionRpc;
import com.shengchao.examstar.rpc.question.api.IQuestionIndexRpc;
import com.shengchao.examstar.rpc.question.api.IQuestionRpc;
import com.shengchao.examstar.rpc.question.api.ISpecialPracticeRpc;
import com.shengchao.examstar.rpc.question.api.ILearningSummaryRpc;
import com.shengchao.examstar.rpc.question.req.*;
import com.shengchao.examstar.rpc.question.resp.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import top.continew.starter.core.validation.CheckUtils;
import top.continew.starter.core.validation.ValidationUtils;
import cn.shengchao.idempotent.annotation.Idempotent;
import top.continew.starter.log.annotation.Log;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import cn.shengchao.examstar.knowledge.application.ExerciseApplicationService;
import cn.shengchao.examstar.knowledge.domain.vo.MasteryStatusEnum;

@RestController
@Slf4j
@CrossOrigin("${project.cross-origin}")
@RequestMapping("/api/${project.version}/question")
public class QuestionController {

    @DubboReference
    private IQuestionRpc questionRpc;

    @DubboReference
    private IErrorQuestionRpc iErrorQuestionRpc;

    @Autowired
    private DistributeNodeInfoService distributeNodeInfoService;

    @Autowired
    private QuestionCorrectAgent questionCorrectAgent;

    @Autowired
    private IAiChatFreeSunRepository iAiChatFreeSunRepository;

    @DubboReference
    private IQuestionIndexRpc iQuestionIndexRpc;

    @DubboReference(timeout = 600000)
    private ISpecialPracticeRpc iSpecialPracticeRpc;

    @DubboReference(timeout = 600000)
    private ILearningSummaryRpc iLearningSummaryRpc;

    @Autowired
    private INodeKnowledgePointRepository iNodeKnowledgePointRepository;

    @Autowired
    private IKnowledgePointRepository iKnowledgePointRepository;
    @Autowired
    IKnowledgePointRepository knowledgePointRepository;

    @Autowired
    private ExerciseApplicationService exerciseApplicationService;

    @Autowired
    private AIWorkflowApplicationService aiWorkflowApplicationService;

    //题集下的题目
    @GetMapping("set:{objId}")
    public List<QuestionListResp> getQuestionListByQuestionSetId(@PathVariable Long objId) throws ExecutionException, InterruptedException {
        return questionRpc.getQuestionListByQuestionSetId(String.valueOf(objId));
    }

    //题集下题目详情
    @GetMapping("{questionId}")
    public QuestionInfoResp getQuestionInfo(@PathVariable Long questionId, @RequestParam long questionSetId) throws ExecutionException, InterruptedException {
        return questionRpc.getQuestionInfo(questionId, questionSetId);
    }

    //做题
    @Idempotent
    @PostMapping("doQuestion")
    public void doQuestion(@RequestBody List<DoQuestionReq> doQuestionReqs) {
        questionRpc.doQuestion(doQuestionReqs);
    }

    //ai批改
    @Log(ignore = true)
    @Idempotent(timeout = 200)
    @PostMapping(value = "/doQuestionAi", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> doQuestionAi(@RequestBody DoQuestionReq doQuestionReq) throws ExecutionException, InterruptedException, NoApiKeyException, UploadFileException {
        AiChatFreeType aiChatFreeType = AiChatFreeType.USER;
        DistributeNodeInfo distributeNodeInfo = distributeNodeInfoService.getDistributeNodeInfoInCode(LoginHelper.getUserId(), List.of(DistributeSaleRoleEnum.ROLE_MKMG, DistributeSaleRoleEnum.ROLE_DSPD, DistributeSaleRoleEnum.ROLE_SLMB));
        if (distributeNodeInfo != null) {
            aiChatFreeType = AiChatFreeType.MEMBER;
        }
        Long freeSum = iAiChatFreeSunRepository.getAiChatFreeCount(aiChatFreeType);
        Long sum = iAiChatFreeSunRepository.getUserDoCount(LoginHelper.getUserId(), DateUtil.beginOfMonth(new Date()), new Date());
        ValidationUtils.throwIf(freeSum - sum <= 0, "本月免费次数已用完!");
        iAiChatFreeSunRepository.doAi(LoginHelper.getUserId(), 2L);
        QuestionInfoResp questionInfoResp = questionRpc.getQuestionInfo(doQuestionReq.getQuestionId(), doQuestionReq.getQuestionSetId());
        //答案
        String userAnswer = doQuestionReq.getUserAnswer();
        //标准答案
        String standardAnswer = questionInfoResp.getAnswer();
        //解析
        String analysis = questionInfoResp.getAnalysis();
        //分值
        Double score = questionInfoResp.getScore();
        Flux<String> flux = questionCorrectAgent.extractKnowledge(standardAnswer, userAnswer, analysis, doQuestionReq.getType(), String.valueOf(score));
        List<String> buffer = new ArrayList<>();
        // 缓存
        Long uid = LoginHelper.getUserId();
        return flux.doOnNext(buffer::add).doOnComplete(() -> {
            Optional<String> aiResult = buffer.stream().reduce(String::concat);
            if (aiResult.isPresent()) {
                String result = aiResult.get();
                Pattern pattern = Pattern.compile("```json\\s*(\\{.*?\\})\\s*```", Pattern.DOTALL);
                Matcher matcher = pattern.matcher(result);
                if (matcher.find()) {
                    String json = matcher.group(1);
                    QuestionCorrectAgent.AiAnalysis aiAnalysis = JSON.parseObject(json, QuestionCorrectAgent.AiAnalysis.class);
                    questionRpc.correct(doQuestionReq, uid, aiAnalysis.getComment(), aiAnalysis.getScore());
                } else {
                    questionRpc.correct(doQuestionReq, uid, result, 0.0);
                }
            }
        });
    }

    //错题本
    @GetMapping("wrongBook")
    @Idempotent(timeout = 200)
    public void addToWrongBook(@RequestParam Long questionId, @RequestParam Long questionSetId, @RequestParam String questionSetName) {
        questionRpc.addToWrongBook(questionId, LoginHelper.getUserId(), questionSetId, questionSetName);
    }

    //错题
    @GetMapping("wrongBookQuestion")
    public List<ErrorQuestionInfoResp> getToWrongBook(ErrorQuestionReq errorQuestionReq) throws ExecutionException, InterruptedException {
        return iErrorQuestionRpc.getErrorQuestionList(errorQuestionReq);
    }

    //错题统计
    @GetMapping("wrongBookStatistics")
    public ErrorQuestionStatistics wrongBookStatistics(@RequestParam Long specificationType) throws ExecutionException, InterruptedException {
        return iErrorQuestionRpc.getErrorQuestionStatistics(specificationType);
    }

    //标记重点
    @GetMapping("markTheHighlights")
    public void markTheHighlights(@RequestParam Long questionId, @RequestParam Long isImportant) {
        iErrorQuestionRpc.markTheHighlights(questionId, isImportant);
    }


    //清空题集做题记录
    @GetMapping("clearQuestionSetRecord")
    public void clearQuestionSetRecord(@RequestParam Long questionSetId) {
        questionRpc.clearQuestionSetRecord(questionSetId);
    }

    //首页统计
    @GetMapping("indexQuestionStatistics")
    public IndexQuestionStatistics indexQuestionStatistics(Long specificationType) throws Exception {
        return iQuestionIndexRpc.getQuestionStatistics(specificationType);
    }

    //知识点统计
    @GetMapping("knowledgeStatistics")
    public PageResult<IndexKnowledge> knowledgeStatistics(IndexKnowledgeReq indexKnowledgeReq) throws Exception {
        KnowledgeReq knowledgeReq = new KnowledgeReq();
        knowledgeReq.setPath(indexKnowledgeReq.getPath());
        knowledgeReq.setSpecificationType(indexKnowledgeReq.getSpecificationType());
        if (StrUtil.isNotBlank(indexKnowledgeReq.getKnowledgeTags())) {
            knowledgeReq.setTags(Arrays.stream(indexKnowledgeReq.getKnowledgeTags().split("-"))
                    .map(Long::parseLong)
                    .toList());
        }
        knowledgeReq.setName(indexKnowledgeReq.getSearchValue());
        knowledgeReq.setSize(indexKnowledgeReq.getSize());
        knowledgeReq.setPage(indexKnowledgeReq.getPage());
        long total = 0;
        Page<Object> page = PageHelper.startPage(knowledgeReq.getPage(), knowledgeReq.getSize());
        List<KnowledgePoint> list = knowledgePointRepository.getKnowledgePointByQuestionLeafList(knowledgeReq);
        total = page.getTotal();
        if (CollUtil.isNotEmpty(list)) {
            List<KnowledgePointDto> dtoList = list.stream().map(point -> {
                KnowledgePointDto dto = new KnowledgePointDto();
                dto.setId(point.getId());
                dto.setName(point.getName());
                return dto;
            }).toList();
            // 使用CompletableFuture异步处理标签信息
            try (ExecutorService executorService = Executors.newFixedThreadPool(dtoList.size())) {
                List<CompletableFuture<Void>> futures = dtoList.stream()
                        .map(dto -> CompletableFuture.supplyAsync(
                                        () -> knowledgePointRepository.getKnowledgePointTagList(dto.getId()),
                                        CompletableFuture.delayedExecutor(0, java.util.concurrent.TimeUnit.MILLISECONDS, executorService)
                                ).thenAccept(tags -> dto.setTags(tags.stream().map(KnowledgeTag::getTag).toList()))
                        ).toList();
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
                List<IndexKnowledge> indexKnowledgeList = iQuestionIndexRpc.getKnowledgeByPointDtos(new JSONArray(dtoList));
                executorService.close();
                return PageResult.of(total, indexKnowledgeList);
            }
        } else {
            return PageResult.of(total, List.of());
        }
    }

    //随堂练习
    @GetMapping("courseNodeKnowledge")
    public List<IndexKnowledge> courseNodeKnowledge(Long courseNodeId) throws Exception {
        List<NodeKnowledgePoint> nodeKnowledgePoint = iNodeKnowledgePointRepository.getNodeKnowledgePoint(courseNodeId);
        if (nodeKnowledgePoint.isEmpty()) {
            return new ArrayList<>();
        }
        List<IndexKnowledge> indexKnowledges = iQuestionIndexRpc.getIndexKnowledgeById(nodeKnowledgePoint.stream().map(NodeKnowledgePoint::getKnowledgePointId).toList());
        List<CompletableFuture<Void>> completableFutures = indexKnowledges.stream().map(indexKnowledge -> CompletableFuture.runAsync(() -> {
            KnowledgePoint point = iKnowledgePointRepository.getKnowledgePoint(indexKnowledge.getQuestionSetId());
            indexKnowledge.setKnowledgeName(point.getName());
            indexKnowledge.setKnowledgeTags(point.getKnowledgeTags().stream().map(KnowledgeTag::getTag).toList());
        })).toList();
        CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();
        return indexKnowledges.stream().filter(indexKnowledge -> indexKnowledge.getQuestionSum() > 0).toList();
    }

    //查看专项题集id
    @GetMapping("specialPractice")
    public SpecialPracticeIdsResp getSpecialPractice(@RequestParam Long objectId) throws ExecutionException, InterruptedException {
        return iSpecialPracticeRpc.getSpecialPracticeIdsByKnowledge(objectId, LoginHelper.getUserId());
    }

    //创建专项题集
    @PostMapping("createSpecialPractice")
    public SpecialPracticeResp createSpecialPractice(@RequestBody SpecialPracticeGenerateReq specialPracticeGenerateReq) throws ExecutionException, InterruptedException {
        specialPracticeGenerateReq.setUserId(LoginHelper.getUserId());
        Long userId = LoginHelper.getUserId();
        AiChatFreeType aiChatFreeType = AiChatFreeType.USER;
        DistributeNodeInfo distributeNodeInfo = distributeNodeInfoService.getDistributeNodeInfoInCode(LoginHelper.getUserId(), List.of(DistributeSaleRoleEnum.ROLE_MKMG, DistributeSaleRoleEnum.ROLE_DSPD, DistributeSaleRoleEnum.ROLE_SLMB));
        if (distributeNodeInfo != null) {
            aiChatFreeType = AiChatFreeType.MEMBER;
        }
        Long freeSum = iAiChatFreeSunRepository.getAiChatFreeCount(aiChatFreeType);
        Long sum = iAiChatFreeSunRepository.getUserDoCount(LoginHelper.getUserId(), DateUtil.beginOfMonth(new Date()), new Date());
        ValidationUtils.throwIf(freeSum - sum <= 0, "本月免费次数已用完!");
        iAiChatFreeSunRepository.doAi(LoginHelper.getUserId(), 2L);
        // 更新单个知识点的掌握度状态为"练习中"(status=2)
        Long knowledgePointId = specialPracticeGenerateReq.getKnowledgeId();
        if (knowledgePointId != null) {
            exerciseApplicationService.updateKnowledgePointMasteryStatus(userId, knowledgePointId, MasteryStatusEnum.PRACTICING);
        } else {
            String knowledge = aiWorkflowApplicationService.getKnowledgeLeafNodesAsJson(
                    UserId.of(userId), SpecificationType.of(specialPracticeGenerateReq.getSpecificationTypeId()));
            specialPracticeGenerateReq.setKnowledge(knowledge);
        }
        SpecialPracticeResp resp = iSpecialPracticeRpc.generateSpecialPractice(specialPracticeGenerateReq);
        questionRpc.clearQuestionSetRecord(resp.getPracticeId());

        return resp;
    }

    //生成学习总结
    @Idempotent(timeout = 2000)
    @PostMapping("generateLearningSummary")
    public LearningSummaryResp generateLearningSummary(@RequestBody LearningSummaryReq learningSummaryReq) throws ExecutionException, InterruptedException, IOException {
        learningSummaryReq.setUserId(LoginHelper.getUserId());
        Long specificationTypeId = learningSummaryReq.getSpecificationTypeId();
        Long userId = LoginHelper.getUserId();
        Long knowledgePointId = learningSummaryReq.getKnowledgeId();
        AiChatFreeType aiChatFreeType = AiChatFreeType.USER;
        DistributeNodeInfo distributeNodeInfo = distributeNodeInfoService.getDistributeNodeInfoInCode(LoginHelper.getUserId(), List.of(DistributeSaleRoleEnum.ROLE_MKMG, DistributeSaleRoleEnum.ROLE_DSPD, DistributeSaleRoleEnum.ROLE_SLMB));
        if (distributeNodeInfo != null) {
            aiChatFreeType = AiChatFreeType.MEMBER;
        }
        Long freeSum = iAiChatFreeSunRepository.getAiChatFreeCount(aiChatFreeType);
        Long sum = iAiChatFreeSunRepository.getUserDoCount(LoginHelper.getUserId(), DateUtil.beginOfMonth(new Date()), new Date());
        ValidationUtils.throwIf(freeSum - sum <= 0, "本月免费次数已用完!");
        iAiChatFreeSunRepository.doAi(LoginHelper.getUserId(), 2L);
        // 查询知识树叶子节点
        KnowledgeReq knowledgeReq = new KnowledgeReq();
        knowledgeReq.setSpecificationType(specificationTypeId);
        List<KnowledgePoint> knowledgePoints = iKnowledgePointRepository.getKnowledgePointByLeafList(knowledgeReq);
        if (knowledgePointId != null) {
            knowledgePoints = knowledgePoints.stream().limit(10).toList();
        }
        // 将知识树JSON存入knowledge字段
        String knowledgeJson = JSON.toJSONString(knowledgePoints);
        learningSummaryReq.setKnowledge(knowledgeJson);
        List<QuestionListResp> questions = questionRpc.getQuestionListByQuestionSetId(String.valueOf(learningSummaryReq.getQuestionSetId()));
        CheckUtils.throwIfEmpty(questions, "请先做题！");
        String question = JSON.toJSONString(questions);
        learningSummaryReq.setQuestionAndAnswer(question);
        LearningSummaryResp learningSummaryResp = iLearningSummaryRpc.generateSummary(learningSummaryReq);
        exerciseApplicationService.batchUpdateKnowledgePointMasteryByWorkflow(userId, question);
        if (knowledgePointId != null) {
            exerciseApplicationService.updateKnowledgePointMasteryStatus(userId, knowledgePointId, MasteryStatusEnum.SUMMARY);
        }
        return learningSummaryResp;
    }

    //获取学习总结
    @GetMapping("getLearningSummary")
    public LearningSummaryResp getLearningSummary(@RequestParam Long questionSetId) throws ExecutionException, InterruptedException {
        return iLearningSummaryRpc.querySummary(LoginHelper.getUserId(), questionSetId);
    }

}
